#include "Scanner.h"
#include <cctype>

Scanner::Scanner() {
}

Scanner::~Scanner() {
}

//Gets next token
string Scanner::next() {
  string current;
  *ss >> current;
  if (!ss->good())
    return "";
  else
    return current;
}

//Gets next line
string Scanner::nextLine() {
  string curr_line;
  getline(*ss, curr_line, '\n');
  if (!ss->good())
    return "";
  else
    return curr_line;
}

//reads file and loads it into istringstream ss
int Scanner::readFile(char* filename) {
  int length;
  char* buffer;
  ifstream is;
  
  is.open(filename, ios::binary);
  
  if (is.is_open() == false)
    return -1;
  
  is.seekg(0, ios::end);
  length = is.tellg();
  is.seekg(0, ios::beg);

  buffer = new char[length];
  is.read(buffer, length);
  is.close();
  
  contents = buffer;
  ss = new istringstream(contents);//new stringstream(contents, stringstream::in | stringstream::out);
  delete[] buffer;
  return 1;
}

//Takes input file and parses it into tokens, non-terminals, and rules
void Scanner::readGrammar() {
  string curr_symbol = " ";
  vector < string > *curr_vector;
  
  while (curr_symbol.compare("") != 0) {
    curr_symbol = next();
    cout << curr_symbol << endl;
    if (curr_symbol.compare("%Tokens") == 0) {
      curr_vector = &tokens;
      continue;
    }
    else if (curr_symbol.compare("%Non-terminals") == 0) {
      curr_vector = &non_terminals;
      continue;
    }
    else if (curr_symbol.compare("%Start") == 0) {
      start_state = next();
      continue;
    }
  
    else if (curr_symbol.compare("%Rules") == 0) {
      break;
    }
    
    curr_vector->push_back(curr_symbol);
  }
  makeRules();
}

//Helper method to make rules
void Scanner::makeRules() {
  //grammar = vector<vector<string> > ();
  string curr_rule;
  while (ss->good()) {
    getline(*ss, curr_rule, '\n');
    if (curr_rule.length() > 0) {
      
      istringstream *rstream = new istringstream(curr_rule);
      //grammar.push_back(vector<string> ());
      string temp;
      string main_rule;
      *rstream >> main_rule;
      
      if(&grammar_map[main_rule] == NULL)
	grammar_map[main_rule] = vector<string>();
      else if(grammar_map[main_rule].size() > 0)
	grammar_map[main_rule].push_back("|");
      
      while (rstream->good()) {
        *rstream >> temp; //out of rstream and into temp
        if (temp != ":")
          grammar_map[main_rule].push_back(temp);
        //grammar[grammar.size() - 1].push_back(temp);
      }
    }
  }
}

//Getter for the grammar
map< string, vector<string> >* Scanner::getGrammar() {
  return &grammar_map;
}

//Debug method to print out rules
void Scanner::printGrammar() {
  
  typedef std::map <std::string, std::vector<std::string> > MapType;
  MapType data = grammar_map;
  
  MapType::const_iterator end = data.end();
  for(MapType::const_iterator it = data.begin(); it != end; ++it) {
    cout << it->first << " -> " << " ";
    
    vector<string> vec = it->second;
    for(int i = 0; i < vec.size(); ++i) {
      cout << vec[i] << " ";
    }
    cout << endl;
  }
  
}

//Getter for Start state
string Scanner::getStartState() {
  return start_state;
}

//Getter for Tokens
vector<string>* Scanner::getTokens() {
  return &tokens;
}

//Getter for non-terminals
vector<string>* Scanner::getNon_terminals() {
  return &non_terminals;
}

//Debug method that prints everything :)
void Scanner::printVectors() {
  cout << endl << "Start symbol: " << start_state << endl;

  cout << endl << "Tokens " << tokens.size() << endl;
  for (vector<string>::iterator token = tokens.begin(); token != tokens.end(); ++token) {
    cout << *token << endl;
  }
  
  cout << endl << "Non-Terminals " << non_terminals.size() << endl;
  for (vector<string>::iterator non_term = non_terminals.begin(); non_term
	 != non_terminals.end(); ++non_term) {
    cout << *non_term << endl;
  }
  cout << endl << endl;
  
  cout << "Grammar" << endl;
  printGrammar();
}

//Matches input to Token symbol
string Scanner::matchSymbol(string symbol) {
  if (checkNumber(symbol))
    return "INTNUM";
  else if (symbol == "begin")
    return "BEGIN";
  else if (symbol == "end")
    return "END";
  else if (symbol == "print")
    return "PRINT";
  else if (symbol == "read")
    return "READ";
  else if (symbol == "(")
    return "LEFTPAR";
  else if (symbol == ")")
    return "RIGHTPAR";
  else if (symbol == ":=")
    return "ASSIGN";
  else if (symbol == ",")
    return "COMMA";
  else if (symbol == ";")
    return "SEMICOLON";
  else if (symbol == "+")
    return "PLUS";
  else if (symbol == "-")
    return "MINUS";
  else if (symbol == "*")
    return "MULTIPLY";
  else if (symbol == "%")
    return "MODULO";
  else if (checkID(symbol))
    return "ID";
  else
    return "NaS";
}

//Check if symbol can be variable/id
bool Scanner::checkID(string symbol) {
  if (symbol.length() > 10) {
    return false;
  } else if (symbol[0] == '_' && symbol.length() == 1 || symbol[0] == '_'
	     && !isalnum(symbol[1])) {
    return false;
  } else if (symbol[0] != '_' && !isalpha(symbol[0])) {
    return false;
  } else {
    return true;
  }
}

//Check if symbol is a number
bool Scanner::checkNumber(string symbol) {
  for (int i = 0; i < symbol.length(); i++) {
    char c = symbol[i];
    if ((int) c < 48 || (int) c > 57)
      return false;
  }
  return true;
}
